package org.shoukaiseki.tools.mybatis.generator.actuator;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.cli.CommandLine;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.shoukaiseki.commons.utils.FileUtils;
import org.shoukaiseki.commons.utils.NameUtils;
import org.shoukaiseki.tools.mybatis.generator.config.GeneratorProperties;
import org.shoukaiseki.tools.mybatis.generator.config.SqlProperties;
import org.shoukaiseki.tools.mybatis.generator.constant.Constants;
import org.shoukaiseki.tools.mybatis.generator.exception.SksException;
import org.shoukaiseki.tools.mybatis.generator.plugin.mysql.MysqlToGeneraterJavaModel;
import org.shoukaiseki.tools.mybatis.generator.plugin.oracle.OracleToGeneraterJavaModel;
import org.shoukaiseki.tools.mybatis.generator.velocity.VelocityInitializer;
import org.shoukaiseki.tools.mybatis.generator.velocity.domain.ColumnInfo;
import org.shoukaiseki.tools.mybatis.generator.velocity.domain.TableInfo;
import org.shoukaiseki.tools.mybatis.generator.velocity.utils.GenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.File;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * <br>
 *
 * @author 蒋カイセキ    Japan-Tokyo  18-10-23 下午2:34<br>
 * ブログ http://www.shoukaiseki.top/<br>
 * E-メール jiang28555@Gmail.com<br>
 **/
@Service
@Slf4j(topic = "org.shoukaiseki.tools.generator")
public class GeneratorActuator {

    @Value("${sks.logger.printError:false")
    private String printError;

    @Autowired
    DataSource dataSource;

    @Resource
    GeneratorProperties generatorProperties;

    @Resource
    CommandLine commandLine;

    public void generator() throws Exception {
        generator(false);
    }


    public void generator(boolean force) throws Exception {
        VelocityInitializer.initVelocity();

        SimpleDateFormat sdf=new SimpleDateFormat(generatorProperties.getDateTimeFormat());

        String path = System.getProperty("user.dir");
        log.debug("path={}",path);
        Connection connection ;
        try {
            connection = dataSource.getConnection();
        }catch (Throwable t){
            throw new SksException("获取数据库连接出错.",t);
        }
        for (SqlProperties sqlProperties:generatorProperties.getLists()) {

            if(commandLine.hasOption("l")||"true".equalsIgnoreCase(printError)){
                log.debug("sqlProperties={}",JSONObject.toJSONString(sqlProperties));
            }

            TableInfo tableInfo=new TableInfo();
            String domainObjectName = sqlProperties.getDomainObjectName();
            tableInfo.setClassName(domainObjectName);
            tableInfo.setClassname(NameUtils.firstLetterLowerCase(domainObjectName));

            // java对象数据传递到模板文件vm
            VelocityContext velocityContext = new VelocityContext();

            velocityContext.put("className", tableInfo.getClassName());
            velocityContext.put("classname", tableInfo.getClassname());
            velocityContext.put("package",sqlProperties.getJavaModelPackage());
            velocityContext.put("javaModelPackage",sqlProperties.getJavaModelPackage());
            velocityContext.put("javaMapperPackage",sqlProperties.getJavaMapperPackage());
            velocityContext.put("author",generatorProperties.getAuthor());
            velocityContext.put("datetime",sdf.format(new Date()));
            velocityContext.put("tableComment", "");
            velocityContext.put("timestamp",System.currentTimeMillis());

            //java代码存放路径
            String saveJavaPath=null;

            String saveJavaMapperPath=null;

            String saveMapperXmlPath=null;

            //不生成mapper 类 就不需要判断这两个配置是否有值
           if(sqlProperties.isGenerateJavaMapper()){

               if(sqlProperties.getJavaMapperPackage()==null){
                  throw new SksException("javaModelPackage 不能为空,其它信息为:\r\t\t\t\t"+ JSONObject.toJSONString(sqlProperties)+"");
               }


               saveJavaMapperPath=FileUtils.savePathFormat(sqlProperties.getJavaMapperPath(),sqlProperties.getJavaMapperPackage(),false);
           }

            if(sqlProperties.isGenerateSqlMap()){
                if(sqlProperties.getSqlMapPackage()==null){
                    throw new SksException("sqlMapPackage 不能为空,其它信息为:\r\t\t\t\t"+ JSONObject.toJSONString(sqlProperties)+"");
                }
                saveMapperXmlPath=FileUtils.savePathFormat(sqlProperties.getSqlMapPath(),sqlProperties.getSqlMapPackage(),true);
            }

            if(sqlProperties.isGenerateJavaModel()){
                if(sqlProperties.getJavaModelPackage()==null){
                    throw new SksException("javaModelPackage 不能为空,其它信息为:\r\t\t\t\t"+ JSONObject.toJSONString(sqlProperties)+"");
                }
                saveJavaPath=FileUtils.savePathFormat(sqlProperties.getJavaModelPath(),sqlProperties.getJavaModelPackage(),false);
            }

            BaseGeneraterJavaModel generaterJavaModel;

            switch (generatorProperties.getDatabaseType()){
                case "oracle":
                    generaterJavaModel=new OracleToGeneraterJavaModel(dataSource.getConnection());

                    try{
                        PreparedStatement ps =  connection.prepareStatement(sqlProperties.getSql());
                        ResultSet resultSet = ps.executeQuery();
                        List<ColumnInfo> columnInfoList = generaterJavaModel.generator(resultSet.getMetaData(), sqlProperties.duplication(), saveJavaPath);
                        columnInfoList.forEach(columnInfo -> {
                            if(columnInfo.getPrimaryKey()){
                                tableInfo.setPrimaryKey(columnInfo);
                            }
                        });
                        velocityContext.put("columns",columnInfoList);
                        velocityContext.put("tables",generaterJavaModel.getTableNameMap());
                        generaterJavaModel.getTableNameMap().keySet().forEach((tableName) -> {

                            velocityContext.put("tableName",tableName);
                        });
                    }catch (Exception e){
                        log.error("sql={}",sqlProperties.getSql());
                        throw e;
                    }

                    break;
                case "mysql":
                    generaterJavaModel=new MysqlToGeneraterJavaModel(dataSource.getConnection());

                    try{
                        PreparedStatement ps =  connection.prepareStatement(sqlProperties.getSql());
                        ResultSet resultSet = ps.executeQuery();
                        List<ColumnInfo> columnInfoList = generaterJavaModel.generator(resultSet.getMetaData(), sqlProperties.duplication(), saveJavaPath);
                        columnInfoList.forEach(columnInfo -> {
                            if(columnInfo.getPrimaryKey()){
                             tableInfo.setPrimaryKey(columnInfo);
                            }
                        });
                        velocityContext.put("columns",columnInfoList);
                        velocityContext.put("tables",generaterJavaModel.getTableNameMap());
                        generaterJavaModel.getTableNameMap().keySet().forEach((tableName) -> {

                            velocityContext.put("tableName",tableName);
                        });
                    }catch (Exception e){
                       log.error("sql={}",sqlProperties.getSql());
                       throw e;
                    }

                    break;
                default:
                    throw new SksException("sks.generator.database-type 未知的数据库类型");
            }

            if(sqlProperties.getPrimaryKey()!=null){
                velocityContext.put("primaryKey", sqlProperties.getPrimaryKey());
            }else{
                velocityContext.put("primaryKey", tableInfo.getPrimaryKey());
            }

            if(sqlProperties.getTableName()!=null){
                velocityContext.put("tableName",sqlProperties.getTableName());
            }



            // 获取模板列表
            List<String> templates = GenUtils.getTemplates();
            for (String template : templates)
            {
                // 渲染模板
                StringWriter sw = new StringWriter();
                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
                tpl.merge(velocityContext, sw);

                if( template.contains("model.java.vm")){
                    FileUtils.mkdirs(saveJavaPath);
                    String fileName=saveJavaPath+"/"+sqlProperties.getDomainObjectName()+".java";

                    if(!FileUtils.exists(fileName)||force){
                        Constants.consoleLogger.debug("{}保存model文件,path={}",Constants.LOGGER_PREFIX,fileName);
                        org.apache.commons.io.FileUtils.writeStringToFile(new File(fileName),sw.toString(),Constants.UTF8);
                        Constants.consoleLogger.debug("{}文件{}保存完成",Constants.LOGGER_PREFIX,fileName);
                    }else{
                        if(!force){
                            Constants.consoleLogger.debug("{}文件已存在,如需强制覆盖,则添加 -o 参数,文件名:{}",Constants.LOGGER_PREFIX,fileName);
                        }
                    }
                }else if(template.contains("Mapper.xml.vm")){
                    if(saveMapperXmlPath!=null){
                        FileUtils.mkdirs(saveMapperXmlPath);
                        String fileName=saveMapperXmlPath+"/"+sqlProperties.getDomainObjectName()+"Mapper.xml";

                        if(!FileUtils.exists(fileName)||force){

                            Constants.consoleLogger.debug("{}保存xml文件,path={}",Constants.LOGGER_PREFIX,fileName);
                            org.apache.commons.io.FileUtils.writeStringToFile(new File(fileName),sw.toString(),Constants.UTF8);
                            Constants.consoleLogger.debug("{}文件{}保存完成",Constants.LOGGER_PREFIX,fileName);
                        }else{
                            if(!force){
                                Constants.consoleLogger.debug("{}文件已存在,如需强制覆盖,则添加 -o 参数,文件名:{}",Constants.LOGGER_PREFIX,fileName);
                            }
                        }
                    }

                }else if(template.contains("Mapper.java.vm")){
                    if(saveJavaMapperPath!=null){

                        FileUtils.mkdirs(saveJavaMapperPath);
                        String fileName=saveJavaMapperPath+"/"+sqlProperties.getDomainObjectName()+"Mapper.java";

                        if(!FileUtils.exists(fileName)||force){
                            Constants.consoleLogger.debug("{}保存mapper文件,path={}",Constants.LOGGER_PREFIX,fileName);
                            org.apache.commons.io.FileUtils.writeStringToFile(new File(fileName),sw.toString(),Constants.UTF8);
                            Constants.consoleLogger.debug("{}文件{}保存完成",Constants.LOGGER_PREFIX,fileName);
                        }else{
                            if(!force){
                                Constants.consoleLogger.debug("{}文件已存在,如需强制覆盖,则添加 -o 参数,文件名:{}",Constants.LOGGER_PREFIX,fileName);
                            }
                        }
                    }
                }
            }
        }


    }

}
